package org.example.auth.service.impl;

import org.example.auth.config.Constant;
import org.example.auth.contract.request.RoleRequestForUserBind;
import org.example.auth.model.entity.UserRole;
import org.example.auth.repository.UserRoleRepository;
import org.example.auth.service.UserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserRoleServiceImpl implements UserRoleService {

    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void refreshForDeleteRoleId(Long roleId) {
        List<UserRole> userRoleList = userRoleRepository.findByRoleId(roleId);
        if (CollectionUtils.isEmpty(userRoleList)) {
            return;
        }
        userRoleRepository.deleteAll(userRoleList);
        // 删除缓存信息
        for (UserRole userRole : userRoleList) {
            redisTemplate.opsForSet().remove(Constant.REDIS_USER_ROLE_PREFIX + userRole.getUserId(), userRole.getRoleId().toString());
        }
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void refreshForDeleteUserId(Long userId) {
        List<UserRole> userRoleList = userRoleRepository.findByUserId(userId);
        if (CollectionUtils.isEmpty(userRoleList)) {
            return;
        }
        userRoleRepository.deleteAll(userRoleList);
        // 删除User 对应所有角色
        Set<Object> members = redisTemplate.opsForSet().members(Constant.REDIS_USER_ROLE_PREFIX + userId);
        redisTemplate.opsForSet().remove(Constant.REDIS_USER_ROLE_PREFIX + userId, members);
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void bindRoleForUser(Long userId, Long roleId) {
        Optional<UserRole> optional = userRoleRepository.findByUserIdAndRoleId(userId, roleId);
        if (optional.isEmpty()) {
            UserRole userRole = new UserRole();
            userRole.setUserId(userId);
            userRole.setRoleId(roleId);
            userRoleRepository.save(userRole);
        }
        redisTemplate.opsForSet().add(Constant.REDIS_USER_ROLE_PREFIX + userId, roleId);
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void unbindRoleForUser(Long userId, Long roleId) {
        Optional<UserRole> optional = userRoleRepository.findByUserIdAndRoleId(userId, roleId);
        optional.ifPresent(userRole -> userRoleRepository.delete(userRole));
        redisTemplate.opsForSet().remove(Constant.REDIS_USER_ROLE_PREFIX + userId, roleId);
    }

    @Override
    public void batchBindRoleForUser(RoleRequestForUserBind request) {
        // 获取用户现在绑定的角色
        List<UserRole> userRoleList = userRoleRepository.findByUserId(request.getUserId());
        // 获取用户现在绑定的角色Id
        Set<Long> bindRoleIdSet = userRoleList.stream().map(UserRole::getRoleId).collect(Collectors.toSet());
        // 待绑定用户权限
        List<UserRole> needBindRoleList = new ArrayList<>();
        for (Long roleId : request.getBindRoleIds()) {
            if (!bindRoleIdSet.contains(roleId)) {
                UserRole userRole = new UserRole();
                userRole.setRoleId(roleId);
                userRole.setUserId(request.getUserId());
                userRole.setDefaultFlag(Boolean.FALSE);
                needBindRoleList.add(userRole);
                bindRoleIdSet.add(roleId);
            }
        }
        // 待解绑用户权限
        List<UserRole> unBindRoleList = new ArrayList<>();
        for (UserRole userRole : userRoleList) {
            if (!request.getBindRoleIds().contains(userRole.getRoleId())) {
                unBindRoleList.add(userRole);
                bindRoleIdSet.remove(userRole.getRoleId());
            }
        }
        userRoleRepository.saveAll(needBindRoleList);
        userRoleRepository.deleteAll(unBindRoleList);
        String redisKey = Constant.REDIS_USER_ROLE_PREFIX + request.getUserId();
        Set<Object> members = redisTemplate.opsForSet().members(redisKey);
        redisTemplate.opsForSet().remove(redisKey, members);
        redisTemplate.opsForSet().add(redisKey, bindRoleIdSet);
    }

}
